#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
专业绩效分析器
Professional Performance Analyzer

专业级回测功能升级 - 绩效分析组件
支持30+专业绩效指标计算，包括基础、高级、风险、交易指标

作者: 后端工程师 + 量化分析师
日期: 2025-08-04
"""

import logging
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any, Tuple
from dataclasses import dataclass
import scipy.stats as stats
from scipy.optimize import minimize
import warnings

warnings.filterwarnings('ignore')
logger = logging.getLogger('户部尚赢.专业回测.绩效分析器')

@dataclass
class PerformanceMetrics:
    """绩效指标结果类"""
    # 基础收益指标
    total_return: float = 0.0
    annualized_return: float = 0.0
    cumulative_return: float = 0.0
    
    # 风险指标
    volatility: float = 0.0
    max_drawdown: float = 0.0
    var_95: float = 0.0
    var_99: float = 0.0
    cvar_95: float = 0.0
    cvar_99: float = 0.0
    downside_volatility: float = 0.0
    
    # 风险调整收益指标
    sharpe_ratio: float = 0.0
    sortino_ratio: float = 0.0
    calmar_ratio: float = 0.0
    information_ratio: float = 0.0
    treynor_ratio: float = 0.0
    
    # 高级指标
    beta: float = 0.0
    alpha: float = 0.0
    tracking_error: float = 0.0
    correlation: float = 0.0
    
    # 交易指标
    win_rate: float = 0.0
    profit_loss_ratio: float = 0.0
    avg_holding_period: float = 0.0
    turnover_rate: float = 0.0
    total_trades: int = 0
    
    # 回撤指标
    max_drawdown_duration: int = 0
    avg_drawdown: float = 0.0
    drawdown_frequency: float = 0.0
    
    # 分布指标
    skewness: float = 0.0
    kurtosis: float = 0.0
    tail_ratio: float = 0.0

class ProfessionalPerformanceAnalyzer:
    """专业绩效分析器"""
    
    def __init__(self, risk_free_rate: float = 0.03, trading_days: int = 252):
        """初始化绩效分析器"""
        self.risk_free_rate = risk_free_rate
        self.trading_days = trading_days
        self.daily_risk_free_rate = risk_free_rate / trading_days
        
        logger.info("✅ 专业绩效分析器初始化完成")
    
    def analyze_performance(self, equity_curve: pd.Series, 
                          benchmark_curve: pd.Series = None,
                          trades: List[Dict] = None) -> PerformanceMetrics:
        """全面绩效分析"""
        try:
            logger.info("🔍 开始专业绩效分析...")
            
            # 计算日收益率
            returns = equity_curve.pct_change().dropna()
            
            # 基准收益率
            benchmark_returns = None
            if benchmark_curve is not None:
                benchmark_returns = benchmark_curve.pct_change().dropna()
                # 对齐时间序列
                common_dates = returns.index.intersection(benchmark_returns.index)
                returns = returns.loc[common_dates]
                benchmark_returns = benchmark_returns.loc[common_dates]
            
            # 创建绩效指标对象
            metrics = PerformanceMetrics()
            
            # 1. 基础收益指标
            self._calculate_basic_metrics(metrics, equity_curve, returns)
            
            # 2. 风险指标
            self._calculate_risk_metrics(metrics, equity_curve, returns)
            
            # 3. 风险调整收益指标
            self._calculate_risk_adjusted_metrics(metrics, returns)
            
            # 4. 基准相关指标
            if benchmark_returns is not None:
                self._calculate_benchmark_metrics(metrics, returns, benchmark_returns)
            
            # 5. 交易指标
            if trades:
                self._calculate_trading_metrics(metrics, trades, equity_curve)
            
            # 6. 回撤指标
            self._calculate_drawdown_metrics(metrics, equity_curve)
            
            # 7. 分布指标
            self._calculate_distribution_metrics(metrics, returns)
            
            logger.info("✅ 专业绩效分析完成")
            return metrics
            
        except Exception as e:
            logger.error(f"❌ 绩效分析失败: {e}")
            return PerformanceMetrics()
    
    def _calculate_basic_metrics(self, metrics: PerformanceMetrics, 
                               equity_curve: pd.Series, returns: pd.Series):
        """计算基础收益指标"""
        try:
            # 总收益率
            metrics.total_return = (equity_curve.iloc[-1] / equity_curve.iloc[0]) - 1
            
            # 累计收益率（同总收益率）
            metrics.cumulative_return = metrics.total_return
            
            # 年化收益率
            years = len(equity_curve) / self.trading_days
            if years > 0:
                metrics.annualized_return = (1 + metrics.total_return) ** (1/years) - 1
            
            logger.debug(f"基础指标: 总收益={metrics.total_return:.4f}, 年化收益={metrics.annualized_return:.4f}")
            
        except Exception as e:
            logger.error(f"❌ 计算基础指标失败: {e}")
    
    def _calculate_risk_metrics(self, metrics: PerformanceMetrics,
                              equity_curve: pd.Series, returns: pd.Series):
        """计算风险指标"""
        try:
            # 波动率（年化）
            metrics.volatility = returns.std() * np.sqrt(self.trading_days)
            
            # 最大回撤
            peak = equity_curve.expanding().max()
            drawdown = (equity_curve - peak) / peak
            metrics.max_drawdown = drawdown.min()
            
            # VaR (Value at Risk)
            metrics.var_95 = np.percentile(returns, 5)
            metrics.var_99 = np.percentile(returns, 1)
            
            # CVaR (Conditional Value at Risk)
            metrics.cvar_95 = returns[returns <= metrics.var_95].mean()
            metrics.cvar_99 = returns[returns <= metrics.var_99].mean()
            
            # 下行波动率
            negative_returns = returns[returns < 0]
            if len(negative_returns) > 0:
                metrics.downside_volatility = negative_returns.std() * np.sqrt(self.trading_days)
            
            logger.debug(f"风险指标: 波动率={metrics.volatility:.4f}, 最大回撤={metrics.max_drawdown:.4f}")
            
        except Exception as e:
            logger.error(f"❌ 计算风险指标失败: {e}")
    
    def _calculate_risk_adjusted_metrics(self, metrics: PerformanceMetrics, returns: pd.Series):
        """计算风险调整收益指标"""
        try:
            # 超额收益
            excess_returns = returns - self.daily_risk_free_rate
            
            # 夏普比率
            if returns.std() > 0:
                metrics.sharpe_ratio = excess_returns.mean() / returns.std() * np.sqrt(self.trading_days)
            
            # 索提诺比率
            if metrics.downside_volatility > 0:
                metrics.sortino_ratio = (metrics.annualized_return - self.risk_free_rate) / metrics.downside_volatility
            
            # 卡尔马比率
            if metrics.max_drawdown < 0:
                metrics.calmar_ratio = metrics.annualized_return / abs(metrics.max_drawdown)
            
            logger.debug(f"风险调整指标: 夏普={metrics.sharpe_ratio:.4f}, 索提诺={metrics.sortino_ratio:.4f}")
            
        except Exception as e:
            logger.error(f"❌ 计算风险调整指标失败: {e}")
    
    def _calculate_benchmark_metrics(self, metrics: PerformanceMetrics,
                                   returns: pd.Series, benchmark_returns: pd.Series):
        """计算基准相关指标"""
        try:
            # Beta系数
            covariance = np.cov(returns, benchmark_returns)[0][1]
            benchmark_variance = np.var(benchmark_returns)
            if benchmark_variance > 0:
                metrics.beta = covariance / benchmark_variance
            
            # Alpha（年化）
            benchmark_annual_return = (1 + benchmark_returns.mean()) ** self.trading_days - 1
            metrics.alpha = metrics.annualized_return - (self.risk_free_rate + 
                                                        metrics.beta * (benchmark_annual_return - self.risk_free_rate))
            
            # 跟踪误差
            tracking_diff = returns - benchmark_returns
            metrics.tracking_error = tracking_diff.std() * np.sqrt(self.trading_days)
            
            # 信息比率
            if metrics.tracking_error > 0:
                metrics.information_ratio = metrics.alpha / metrics.tracking_error
            
            # 特雷诺比率
            if metrics.beta > 0:
                metrics.treynor_ratio = (metrics.annualized_return - self.risk_free_rate) / metrics.beta
            
            # 相关性
            metrics.correlation = np.corrcoef(returns, benchmark_returns)[0][1]
            
            logger.debug(f"基准指标: Beta={metrics.beta:.4f}, Alpha={metrics.alpha:.4f}")
            
        except Exception as e:
            logger.error(f"❌ 计算基准指标失败: {e}")
    
    def _calculate_trading_metrics(self, metrics: PerformanceMetrics,
                                 trades: List[Dict], equity_curve: pd.Series):
        """计算交易指标"""
        try:
            if not trades:
                return
            
            metrics.total_trades = len(trades)
            
            # 提取交易盈亏
            trade_pnls = [trade.get('pnl', 0) for trade in trades]
            winning_trades = [pnl for pnl in trade_pnls if pnl > 0]
            losing_trades = [pnl for pnl in trade_pnls if pnl < 0]
            
            # 胜率
            metrics.win_rate = len(winning_trades) / len(trades) if trades else 0
            
            # 盈亏比
            if losing_trades:
                avg_win = np.mean(winning_trades) if winning_trades else 0
                avg_loss = np.mean(losing_trades)
                metrics.profit_loss_ratio = abs(avg_win / avg_loss) if avg_loss != 0 else 0
            
            # 平均持仓时间
            holding_periods = []
            for trade in trades:
                if 'entry_date' in trade and 'exit_date' in trade:
                    entry_date = pd.to_datetime(trade['entry_date'])
                    exit_date = pd.to_datetime(trade['exit_date'])
                    holding_periods.append((exit_date - entry_date).days)
            
            if holding_periods:
                metrics.avg_holding_period = np.mean(holding_periods)
            
            # 换手率（年化）
            total_traded_value = sum([abs(trade.get('value', 0)) for trade in trades])
            avg_portfolio_value = equity_curve.mean()
            if avg_portfolio_value > 0:
                daily_turnover = total_traded_value / len(equity_curve) / avg_portfolio_value
                metrics.turnover_rate = daily_turnover * self.trading_days
            
            logger.debug(f"交易指标: 胜率={metrics.win_rate:.4f}, 盈亏比={metrics.profit_loss_ratio:.4f}")
            
        except Exception as e:
            logger.error(f"❌ 计算交易指标失败: {e}")
    
    def _calculate_drawdown_metrics(self, metrics: PerformanceMetrics, equity_curve: pd.Series):
        """计算回撤指标"""
        try:
            # 计算回撤序列
            peak = equity_curve.expanding().max()
            drawdown = (equity_curve - peak) / peak
            
            # 最大回撤持续时间
            in_drawdown = drawdown < 0
            drawdown_periods = []
            current_period = 0
            
            for is_dd in in_drawdown:
                if is_dd:
                    current_period += 1
                else:
                    if current_period > 0:
                        drawdown_periods.append(current_period)
                        current_period = 0
            
            if current_period > 0:
                drawdown_periods.append(current_period)
            
            if drawdown_periods:
                metrics.max_drawdown_duration = max(drawdown_periods)
                metrics.avg_drawdown = np.mean([drawdown[drawdown < 0].mean()] if any(drawdown < 0) else [0])
                metrics.drawdown_frequency = len(drawdown_periods) / len(equity_curve) * self.trading_days
            
            logger.debug(f"回撤指标: 最大回撤持续={metrics.max_drawdown_duration}天")
            
        except Exception as e:
            logger.error(f"❌ 计算回撤指标失败: {e}")
    
    def _calculate_distribution_metrics(self, metrics: PerformanceMetrics, returns: pd.Series):
        """计算分布指标"""
        try:
            # 偏度
            metrics.skewness = stats.skew(returns)
            
            # 峰度
            metrics.kurtosis = stats.kurtosis(returns)
            
            # 尾部比率（95%分位数 / 5%分位数的绝对值比）
            p95 = np.percentile(returns, 95)
            p5 = np.percentile(returns, 5)
            if p5 != 0:
                metrics.tail_ratio = abs(p95 / p5)
            
            logger.debug(f"分布指标: 偏度={metrics.skewness:.4f}, 峰度={metrics.kurtosis:.4f}")
            
        except Exception as e:
            logger.error(f"❌ 计算分布指标失败: {e}")
    
    def calculate_rolling_metrics(self, equity_curve: pd.Series, 
                                window: int = 252) -> pd.DataFrame:
        """计算滚动绩效指标"""
        try:
            logger.info(f"🔄 计算滚动绩效指标，窗口期: {window}天")
            
            returns = equity_curve.pct_change().dropna()
            
            rolling_metrics = pd.DataFrame(index=returns.index)
            
            # 滚动年化收益率
            rolling_metrics['annualized_return'] = returns.rolling(window).apply(
                lambda x: (1 + x.mean()) ** self.trading_days - 1
            )
            
            # 滚动波动率
            rolling_metrics['volatility'] = returns.rolling(window).std() * np.sqrt(self.trading_days)
            
            # 滚动夏普比率
            rolling_metrics['sharpe_ratio'] = returns.rolling(window).apply(
                lambda x: (x.mean() - self.daily_risk_free_rate) / x.std() * np.sqrt(self.trading_days)
            )
            
            # 滚动最大回撤
            rolling_metrics['max_drawdown'] = equity_curve.rolling(window).apply(
                lambda x: ((x - x.expanding().max()) / x.expanding().max()).min()
            )
            
            logger.info("✅ 滚动绩效指标计算完成")
            return rolling_metrics
            
        except Exception as e:
            logger.error(f"❌ 计算滚动指标失败: {e}")
            return pd.DataFrame()
    
    def compare_strategies(self, strategy_results: Dict[str, pd.Series]) -> pd.DataFrame:
        """策略对比分析"""
        try:
            logger.info(f"📊 开始策略对比分析，策略数量: {len(strategy_results)}")
            
            comparison_data = []
            
            for strategy_name, equity_curve in strategy_results.items():
                metrics = self.analyze_performance(equity_curve)
                
                comparison_data.append({
                    'Strategy': strategy_name,
                    'Total Return': f"{metrics.total_return:.2%}",
                    'Annualized Return': f"{metrics.annualized_return:.2%}",
                    'Volatility': f"{metrics.volatility:.2%}",
                    'Sharpe Ratio': f"{metrics.sharpe_ratio:.3f}",
                    'Max Drawdown': f"{metrics.max_drawdown:.2%}",
                    'Win Rate': f"{metrics.win_rate:.2%}",
                    'Total Trades': metrics.total_trades
                })
            
            comparison_df = pd.DataFrame(comparison_data)
            
            logger.info("✅ 策略对比分析完成")
            return comparison_df
            
        except Exception as e:
            logger.error(f"❌ 策略对比分析失败: {e}")
            return pd.DataFrame()
    
    def generate_performance_report(self, metrics: PerformanceMetrics) -> Dict[str, Any]:
        """生成绩效报告"""
        try:
            report = {
                'summary': {
                    'total_return': f"{metrics.total_return:.2%}",
                    'annualized_return': f"{metrics.annualized_return:.2%}",
                    'volatility': f"{metrics.volatility:.2%}",
                    'sharpe_ratio': f"{metrics.sharpe_ratio:.3f}",
                    'max_drawdown': f"{metrics.max_drawdown:.2%}"
                },
                'risk_metrics': {
                    'var_95': f"{metrics.var_95:.4f}",
                    'var_99': f"{metrics.var_99:.4f}",
                    'cvar_95': f"{metrics.cvar_95:.4f}",
                    'cvar_99': f"{metrics.cvar_99:.4f}",
                    'downside_volatility': f"{metrics.downside_volatility:.2%}"
                },
                'risk_adjusted_metrics': {
                    'sortino_ratio': f"{metrics.sortino_ratio:.3f}",
                    'calmar_ratio': f"{metrics.calmar_ratio:.3f}",
                    'information_ratio': f"{metrics.information_ratio:.3f}",
                    'treynor_ratio': f"{metrics.treynor_ratio:.3f}"
                },
                'trading_metrics': {
                    'win_rate': f"{metrics.win_rate:.2%}",
                    'profit_loss_ratio': f"{metrics.profit_loss_ratio:.2f}",
                    'avg_holding_period': f"{metrics.avg_holding_period:.1f} days",
                    'turnover_rate': f"{metrics.turnover_rate:.2f}",
                    'total_trades': metrics.total_trades
                },
                'distribution_metrics': {
                    'skewness': f"{metrics.skewness:.3f}",
                    'kurtosis': f"{metrics.kurtosis:.3f}",
                    'tail_ratio': f"{metrics.tail_ratio:.2f}"
                }
            }
            
            return report
            
        except Exception as e:
            logger.error(f"❌ 生成绩效报告失败: {e}")
            return {}

# 使用示例
if __name__ == "__main__":
    # 创建绩效分析器
    analyzer = ProfessionalPerformanceAnalyzer(risk_free_rate=0.03)
    
    # 生成模拟数据
    dates = pd.date_range('2024-01-01', '2024-12-31', freq='D')
    returns = np.random.normal(0.0008, 0.02, len(dates))  # 模拟日收益率
    equity_curve = pd.Series(1000000 * (1 + returns).cumprod(), index=dates)
    
    # 基准数据
    benchmark_returns = np.random.normal(0.0005, 0.015, len(dates))
    benchmark_curve = pd.Series(1000000 * (1 + benchmark_returns).cumprod(), index=dates)
    
    # 模拟交易数据
    trades = [
        {'entry_date': '2024-01-15', 'exit_date': '2024-01-20', 'pnl': 1500, 'value': 50000},
        {'entry_date': '2024-02-01', 'exit_date': '2024-02-10', 'pnl': -800, 'value': 45000},
        {'entry_date': '2024-03-01', 'exit_date': '2024-03-15', 'pnl': 2200, 'value': 55000}
    ]
    
    # 执行绩效分析
    metrics = analyzer.analyze_performance(equity_curve, benchmark_curve, trades)
    
    # 生成报告
    report = analyzer.generate_performance_report(metrics)
    
    print("✅ 专业绩效分析完成")
    print(f"总收益率: {metrics.total_return:.2%}")
    print(f"年化收益率: {metrics.annualized_return:.2%}")
    print(f"夏普比率: {metrics.sharpe_ratio:.3f}")
    print(f"最大回撤: {metrics.max_drawdown:.2%}")
    print(f"胜率: {metrics.win_rate:.2%}")
